home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / clang / tkern091.zip / SRC / WINDOW.C < prev    next >
Text File  |  1994-03-17  |  30KB  |  1,384 lines

  1. /*
  2.  *  This file forms part of "TKERN" - "Troy's Kernel for Windows".
  3.  *
  4.  *  Copyright (C) 1994  Troy Rollo <troy@cbme.unsw.EDU.AU>
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <memory.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <errno.h>
  27. #include <sys/tfile.h>
  28. #include <sys/tdevice.h>
  29. #include <sys/tkwin.h>
  30.  
  31. static    BOOL    bRegistered = 0;
  32. extern    HINSTANCE    hInstance;
  33. extern    int    nError;
  34. extern    void    UnlockManager(void);
  35. extern    void    LockManager(void);
  36. extern    void    FlushMessages(void);
  37. extern    void    tkern_wakeup_call(void);
  38. static    int    window_destroy(HWND hWnd);
  39.  
  40. #define    SC_COPY    5000
  41. #define    SC_PASTE    5001
  42. #define    SC_COPYPASTE    5002
  43.  
  44. #define    DEF_MAXLINES    100
  45. #define    DEF_SCROLLLINES    5
  46.  
  47. struct    line
  48. {
  49.     struct    line *plNext;
  50.     struct    line *plPrev;
  51.     char    *pchLine;
  52. };
  53.  
  54. struct    per_window
  55. {
  56.     struct    line    *pw_head;
  57.     struct    line    *pw_tail;
  58.     struct    line    *pw_inhead;
  59.     struct    line    *pw_intail;
  60.     struct    line    *pw_history;
  61.     struct    line    *pw_hishead;
  62.     struct    line    *pw_histail;
  63.     int    nUnscrolledLines;
  64.     int    nHistory;
  65.     int    nHistMax;
  66.     int    nScrollLines;
  67.     int    nLines;            /* Counter so we can keep the list reasonable */
  68.     int    nLinesMax;
  69.     int    cxChar;
  70.     int    cyChar;
  71.     int    nScrollPos;
  72.     HWND    hEdit;
  73.     int    xEditStart;
  74.     POINT    ptMarkStart;
  75.     POINT    ptMarkEnd;
  76.     BOOL    bMarkValid;
  77.     BOOL    bHaveMouse;
  78.     BOOL    bProgramClosed;
  79. };
  80.  
  81. #define    ENTER_HIT    WM_USER + 1000
  82. #define    UP_HIT        WM_USER + 1001
  83. #define DOWN_HIT    WM_USER + 1002
  84.  
  85. WNDPROC    NormalEditWndProc = 0;
  86.  
  87. FARPROC    FakeEditThunk = 0;
  88.  
  89. int    far    pascal    _export
  90. FakeEditWndProc(    HWND    hWnd,
  91.             UINT    wMsg,
  92.             WPARAM    wParam,
  93.             LPARAM    lParam)
  94. {
  95.     if (wMsg == WM_KEYDOWN)
  96.     {
  97.         if (wParam == VK_UP)
  98.         {
  99.             SendMessage(GetParent(hWnd), UP_HIT, 0, 0);
  100.             return 0;
  101.         }
  102.         else if (wParam == VK_DOWN)
  103.         {
  104.             SendMessage(GetParent(hWnd), DOWN_HIT, 0, 0);
  105.             return 0;
  106.         }
  107.     }
  108.     if (wMsg == WM_CHAR)
  109.     {
  110.         if (wParam == VK_RETURN)
  111.         {
  112.             SendMessage(GetParent(hWnd), ENTER_HIT, 0, 0);
  113.             return 0;
  114.         }
  115.         else if (wParam == VK_TAB)
  116.         {
  117.             SendMessage(hWnd, EM_REPLACESEL, 0, (long) "\t");
  118.             return 0;
  119.         }
  120.     }
  121.     return (*NormalEditWndProc)(hWnd, wMsg, wParam, lParam);
  122. }
  123.  
  124. static    void
  125. MoveMark(struct per_window *pw,
  126.      int nLines)
  127. {
  128.     if (pw->bMarkValid)
  129.     {
  130.         pw->ptMarkStart.y += nLines;
  131.         pw->ptMarkEnd.y += nLines;
  132.     }
  133. }
  134.  
  135. static    void
  136. screen_to_row(    HWND    hWnd,
  137.         struct    per_window *pw,
  138.         int    x,
  139.         int    y,
  140.         int    *xOut,
  141.         int    *yOut)
  142. {
  143.     RECT    rcClient;
  144.     int    cyLastRow;
  145.     struct line *pl;
  146.     int    i, j;
  147.  
  148.     GetClientRect(hWnd, &rcClient);
  149.  
  150.     y = rcClient.bottom - y;
  151.     cyLastRow = pw->cyChar + pw->cyChar / 5 * 2;
  152.     if (y < cyLastRow)
  153.     {
  154.         *yOut = 0;
  155.     }
  156.     else
  157.     {
  158.         *yOut = (y - cyLastRow) / pw->cyChar + 1;
  159.     }
  160.  
  161.     if (*yOut > 0)
  162.         *yOut += pw->nScrollPos;
  163.  
  164.     for (i = *yOut, pl = pw->pw_tail;
  165.          i && pl;
  166.          i--, pl = pl->plPrev);
  167.  
  168.     if (!pl || !pl->pchLine)
  169.     {
  170.         *xOut = 0;
  171.         return;
  172.     }
  173.  
  174.     x = x / pw->cxChar;
  175.  
  176.     for (i = j = 0; x > j && pl->pchLine[i]; i++)
  177.     {
  178.         if (pl->pchLine[i] == '\t')
  179.             j += 8 - j % 8;
  180.         else
  181.             j++;
  182.     }
  183.     *xOut = i;
  184. }
  185.  
  186. static    void
  187. RedrawPoints(    HWND    hWnd,
  188.         struct per_window *pw,
  189.         POINT    ptStart_,
  190.         POINT    ptEnd_)
  191. {
  192.     POINT    ptStart, ptEnd;
  193.     RECT    rcRedraw;
  194.  
  195.     if (ptStart_.y > ptEnd_.y)
  196.     {
  197.         ptStart = ptStart_;
  198.         ptEnd = ptEnd_;
  199.     }
  200.     else if (ptStart_.y < ptEnd_.y)
  201.     {
  202.         ptStart = ptEnd_;
  203.         ptEnd = ptStart_;
  204.     }
  205.     else if (ptStart_.x < ptEnd_.x)
  206.     {
  207.         ptStart = ptStart_;
  208.         ptEnd = ptEnd_;
  209.     }
  210.     else
  211.     {
  212.         ptStart = ptEnd_;
  213.         ptEnd = ptStart_;
  214.     }
  215.     if (ptEnd.y > 0)
  216.     {
  217.         ptEnd.y -= pw->nScrollPos;
  218.         if (ptEnd.y < 0)
  219.             ptEnd.y = 0;
  220.     }
  221.     if (ptStart.y > 0)
  222.     {
  223.         ptStart.y -= pw->nScrollPos;
  224.         if (ptStart.y < 1)
  225.             ptStart.y = 1;
  226.     }
  227.  
  228.     if (ptStart.y < ptEnd.y)
  229.         return;
  230.     GetClientRect(hWnd, &rcRedraw);
  231.     rcRedraw.top = rcRedraw.bottom - pw->cyChar * (ptStart.y + 1) - pw->cyChar / 5 * 2;
  232.     if (ptEnd.y)
  233.         rcRedraw.bottom -= pw->cyChar * ptEnd.y + pw->cyChar / 5 * 2;
  234.     InvalidateRect(hWnd, &rcRedraw, TRUE);
  235. }
  236.  
  237. static    void
  238. MouseDown(    HWND    hWnd,
  239.         struct per_window *pw,
  240.         int    x,
  241.         int    y)
  242. {
  243.     if (pw->bMarkValid)
  244.     {
  245.         pw->bMarkValid = FALSE;
  246.         RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
  247.     }
  248.     screen_to_row(hWnd, pw, x, y, &pw->ptMarkStart.x, &pw->ptMarkStart.y);
  249.     pw->ptMarkEnd = pw->ptMarkStart;
  250.     RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
  251.     SetCapture(hWnd);
  252.     pw->bHaveMouse = TRUE;
  253.     pw->bMarkValid = TRUE;
  254. }
  255.  
  256. static    void
  257. MouseMove(    HWND    hWnd,
  258.         struct per_window *pw,
  259.         int    x,
  260.         int    y)
  261. {
  262.     POINT    ptTemp;
  263.  
  264.     ptTemp = pw->ptMarkEnd;
  265.     screen_to_row(hWnd, pw, x, y, &pw->ptMarkEnd.x, &pw->ptMarkEnd.y);
  266.     RedrawPoints(hWnd, pw, ptTemp, pw->ptMarkEnd);
  267. }
  268.  
  269. static    void
  270. MouseUp(struct per_window *pw)
  271. {
  272.     ReleaseCapture();
  273.     pw->bHaveMouse = FALSE;
  274. }
  275.         
  276.  
  277. static    void
  278. get_mark_coordinates(    struct    per_window *pw,
  279.             POINT    *ptOne,
  280.             POINT    *ptTwo)
  281. {
  282.     if (pw->ptMarkStart.y > pw->ptMarkEnd.y)
  283.     {
  284.         *ptOne = pw->ptMarkStart;
  285.         *ptTwo = pw->ptMarkEnd;
  286.     }
  287.     else if (pw->ptMarkStart.y < pw->ptMarkEnd.y)
  288.     {
  289.         *ptOne = pw->ptMarkEnd;
  290.         *ptTwo = pw->ptMarkStart;
  291.     }
  292.     else if (pw->ptMarkStart.x < pw->ptMarkEnd.x)
  293.     {
  294.         *ptOne = pw->ptMarkStart;
  295.         *ptTwo = pw->ptMarkEnd;
  296.     }
  297.     else
  298.     {
  299.         *ptOne = pw->ptMarkEnd;
  300.         *ptTwo = pw->ptMarkStart;
  301.     }
  302. }
  303.  
  304.  
  305. static    int
  306. is_in_mark(    int    iRow,
  307.         struct per_window *pw,
  308.         int    *iMarkBoundary1,
  309.         int    *iMarkBoundary2)
  310. {
  311.     POINT    ptStart, ptEnd;
  312.  
  313.     if (!pw->bMarkValid)
  314.         return 0;
  315.     get_mark_coordinates(pw, &ptStart, &ptEnd);
  316.     if (ptStart.y > ptEnd.y)
  317.     {
  318.         if (ptEnd.y > iRow ||
  319.             ptStart.y < iRow)
  320.             return 0;
  321.         if (ptStart.y == iRow)
  322.         {
  323.             *iMarkBoundary1 = ptStart.x;
  324.             return 1;
  325.         }
  326.         if (ptEnd.y == iRow)
  327.         {
  328.             *iMarkBoundary1 = ptEnd.x;
  329.             return 2;
  330.         }
  331.         return 3;
  332.     }
  333.     else if (ptStart.y == iRow)
  334.     {
  335.         *iMarkBoundary1 = ptStart.x;
  336.         *iMarkBoundary2 = ptEnd.x;
  337.         return 4;
  338.     }
  339.     else
  340.     {
  341.         return 0;
  342.     }
  343. }
  344.  
  345. static    void
  346. PlaceEdit(    HWND    hWnd,
  347.         struct per_window *pw)
  348. {
  349.     RECT    rcLoc;
  350.  
  351.     GetClientRect(hWnd, &rcLoc);
  352.     rcLoc.left = pw->xEditStart;
  353.     rcLoc.top = rcLoc.bottom - pw->cyChar - pw->cyChar / 5;
  354.     if (pw->hEdit)
  355.     {
  356.         MoveWindow(pw->hEdit,
  357.                 rcLoc.left, rcLoc.top,
  358.                 rcLoc.right - rcLoc.left + 1,
  359.                 rcLoc.bottom - rcLoc.top + 1,
  360.                 TRUE);
  361.     }
  362.     else
  363.     {
  364.         pw->hEdit = CreateWindow(    "EDIT",
  365.                         "",
  366.                         WS_VISIBLE |
  367.                          WS_CHILD |
  368.                          ES_AUTOHSCROLL |
  369.                          ES_LEFT,
  370.                         rcLoc.left,
  371.                         rcLoc.top,
  372.                         rcLoc.right - rcLoc.left,
  373.                         rcLoc.bottom - rcLoc.top,
  374.                         hWnd,
  375.                         (HMENU) 100,
  376.                         hInstance,
  377.                         0
  378.                     );
  379.         if (!NormalEditWndProc)
  380.         {
  381.             NormalEditWndProc = (WNDPROC)
  382.                 GetWindowLong(pw->hEdit, GWL_WNDPROC);
  383.         }
  384.         if (!FakeEditThunk)
  385.         {
  386.             FakeEditThunk = MakeProcInstance((FARPROC) FakeEditWndProc, hInstance);
  387.         }
  388.         SetWindowLong(pw->hEdit, GWL_WNDPROC, (long) FakeEditThunk);
  389.     }
  390. }
  391.  
  392. static    void
  393. PaintWindow(    HWND    hWnd,
  394.         struct per_window *pw)
  395. {
  396.     PAINTSTRUCT    ps;
  397.     TEXTMETRIC    tm;
  398.     LOGFONT        lf;
  399.     int        cyChar;
  400.     int        cyInch;
  401.     int        yLocation;
  402.     int        nRows;
  403.     RECT        rcClient;
  404.     HFONT        hFont, hOldFont;
  405.     int        iRow, iTemp, iTotal;
  406.     struct line    *pl;
  407.     LONG        xExtent, xExtent2;
  408.     BOOL        bBottom = TRUE;
  409.     int        iMarkBoundary1, iMarkBoundary2;
  410.     COLORREF    crBG, crFG, crFGHigh, crBGHigh;
  411.  
  412.     crFG = GetSysColor(COLOR_WINDOWTEXT);
  413.     crBG = GetSysColor(COLOR_WINDOW);
  414.     crFGHigh = GetSysColor(COLOR_HIGHLIGHTTEXT);
  415.     crBGHigh = GetSysColor(COLOR_HIGHLIGHT);
  416.     if (pw->nUnscrolledLines)
  417.     {
  418.         if (!pw->nScrollPos)
  419.             ScrollWindow(hWnd, 0, -pw->nUnscrolledLines * pw->cyChar, 0, 0);
  420.         pw->nUnscrolledLines = 0;
  421.         PlaceEdit(hWnd, pw);
  422.         UpdateWindow(hWnd);
  423.     }
  424.     BeginPaint(hWnd, &ps);
  425.  
  426.     cyInch = GetDeviceCaps(ps.hdc, LOGPIXELSY);
  427.  
  428.     memset(&lf, 0, sizeof(lf));
  429.     lf.lfHeight = MulDiv(cyInch, 12, 72);
  430.     strcpy(lf.lfFaceName, "System");
  431.     lf.lfPitchAndFamily = FIXED_PITCH;
  432.     hFont = CreateFontIndirect(&lf);
  433.     hOldFont = SelectFont(ps.hdc, hFont);
  434.     GetTextMetrics(ps.hdc, &tm);
  435.     cyChar = tm.tmHeight + tm.tmExternalLeading;
  436.     GetClientRect(hWnd, &rcClient);
  437.     pw->cxChar = tm.tmAveCharWidth;
  438.     pw->cyChar = cyChar;
  439.     pl = pw->pw_tail;
  440.  
  441.     if (pw->pw_tail->pchLine)
  442.         xExtent = GetTabbedTextExtent(ps.hdc, 
  443.                           pl->pchLine,
  444.                           strlen(pl->pchLine),
  445.                           0, 0);
  446.     else
  447.         xExtent = 0;
  448.     pw->xEditStart = LOWORD(xExtent);
  449.  
  450.     PlaceEdit(hWnd, pw);
  451.  
  452.     nRows = (rcClient.bottom - ps.rcPaint.top) / cyChar + 1;
  453.  
  454.     for (iRow = 0, iTotal = 0, pl = pw->pw_tail,
  455.           yLocation = rcClient.bottom - cyChar;
  456.          pl && iTotal < nRows;
  457.          iRow++, iTotal++, pl = pl->plPrev)
  458.     {
  459.         if (iRow == 1 && pw->nScrollPos)
  460.         {
  461.             for (iTemp = 0; iTemp < pw->nScrollPos && pl; iTemp++, pl = pl->plPrev, iRow++);
  462.             if (!pl)
  463.                 break;
  464.         }
  465.         if (bBottom)
  466.         {
  467.             yLocation -= cyChar / 5;
  468.         }
  469.         if (pl->pchLine)
  470.         {
  471.             switch(is_in_mark(iRow, pw, &iMarkBoundary1, &iMarkBoundary2))
  472.             {
  473.             case 0: /* Not in a marked area */
  474.                 SetTextColor(ps.hdc, crFG);
  475.                 SetBkColor(ps.hdc, crBG);
  476.                 TabbedTextOut(ps.hdc, 0, yLocation,
  477.                           pl->pchLine, strlen(pl->pchLine),
  478.                           0, 0, 0);
  479.                 break;
  480.  
  481.             case 1: /* First line in a marked area */
  482.                 SetTextColor(ps.hdc, crFG);
  483.                 SetBkColor(ps.hdc, crBG);
  484.                 TabbedTextOut(ps.hdc, 0, yLocation,
  485.                           pl->pchLine, iMarkBoundary1,
  486.                           0, 0, 0);
  487.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  488.                           pl->pchLine,
  489.                           iMarkBoundary1,
  490.                           0, 0);
  491.                 SetTextColor(ps.hdc, crFGHigh);
  492.                 SetBkColor(ps.hdc, crBGHigh);
  493.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  494.                         pl->pchLine + iMarkBoundary1,
  495.                         strlen(pl->pchLine) - iMarkBoundary1,
  496.                         0, 0, 0);
  497.                 break;
  498.  
  499.             case 2: /* Last line in a marked area */
  500.                 SetTextColor(ps.hdc, crFGHigh);
  501.                 SetBkColor(ps.hdc, crBGHigh);
  502.                 TabbedTextOut(ps.hdc, 0, yLocation,
  503.                           pl->pchLine, iMarkBoundary1,
  504.                           0, 0, 0);
  505.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  506.                           pl->pchLine,
  507.                           iMarkBoundary1,
  508.                           0, 0);
  509.                 SetTextColor(ps.hdc, crFG);
  510.                 SetBkColor(ps.hdc, crBG);
  511.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  512.                         pl->pchLine + iMarkBoundary1,
  513.                         strlen(pl->pchLine) - iMarkBoundary1,
  514.                         0, 0, 0);
  515.                 break;
  516.  
  517.             case 3:    /* Entire line is in a marked area */
  518.                 SetTextColor(ps.hdc, crFGHigh);
  519.                 SetBkColor(ps.hdc, crBGHigh);
  520.                 TabbedTextOut(ps.hdc, 0, yLocation,
  521.                           pl->pchLine, strlen(pl->pchLine),
  522.                           0, 0, 0);
  523.                 break;
  524.  
  525.             case 4: /* Both first and last line in marked area */
  526.                 SetTextColor(ps.hdc, crFG);
  527.                 SetBkColor(ps.hdc, crBG);
  528.                 TabbedTextOut(ps.hdc, 0, yLocation,
  529.                           pl->pchLine, iMarkBoundary1,
  530.                           0, 0, 0);
  531.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  532.                           pl->pchLine,
  533.                           iMarkBoundary1,
  534.                           0, 0);
  535.                 SetTextColor(ps.hdc, crFGHigh);
  536.                 SetBkColor(ps.hdc, crBGHigh);
  537.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  538.                         pl->pchLine + iMarkBoundary1,
  539.                         iMarkBoundary2 - iMarkBoundary1,
  540.                         0, 0, 0);
  541.                 xExtent2 = GetTabbedTextExtent(ps.hdc, 
  542.                           pl->pchLine + iMarkBoundary1,
  543.                           iMarkBoundary2 - iMarkBoundary1,
  544.                           0, 0);
  545.                 SetTextColor(ps.hdc, crFG);
  546.                 SetBkColor(ps.hdc, crBG);
  547.                 TabbedTextOut(ps.hdc, LOWORD(xExtent) + LOWORD(xExtent2),
  548.                         yLocation,
  549.                         pl->pchLine + iMarkBoundary2,
  550.                         strlen(pl->pchLine) - iMarkBoundary2,
  551.                         0, 0, 0);
  552.                 break;
  553.             }
  554.         }
  555.         yLocation -= cyChar;
  556.         if (bBottom)
  557.         {
  558.             yLocation -= cyChar / 5;
  559.             bBottom = FALSE;
  560.         }
  561.     }
  562.  
  563.     SelectFont(ps.hdc, hOldFont);
  564.     DeleteFont(hFont);
  565.     EndPaint(hWnd, &ps);
  566. }
  567.  
  568. void
  569. GotLine(struct per_window *pw)
  570. {
  571.     struct    line *plTemp, *plNew;
  572.     char    *pchData;
  573.     int    nLen;
  574.  
  575.     pw->pw_history = 0;
  576.     nLen = GetWindowTextLength(pw->hEdit);
  577.  
  578.     /* Once for the input queue */
  579.     pchData = (char *) malloc(nLen + 1);
  580.     GetWindowText(pw->hEdit, pchData, nLen + 1);
  581.     pchData[nLen] = 0;
  582.     plNew = (struct line *) malloc(sizeof(struct line));
  583.     plNew->plNext = 0;
  584.     plNew->plPrev = pw->pw_intail;
  585.     plNew->pchLine = pchData;
  586.     if (pw->pw_intail)
  587.         pw->pw_intail->plNext = plNew;
  588.     else
  589.         pw->pw_inhead = plNew;
  590.     pw->pw_intail = plNew;
  591.  
  592.     /* Once for the history list */
  593.     pchData = (char *) malloc(nLen + 1);
  594.     GetWindowText(pw->hEdit, pchData, nLen + 1);
  595.     pchData[nLen] = 0;
  596.     plNew = (struct line *) malloc(sizeof(struct line));
  597.     plNew->plNext = 0;
  598.     plNew->plPrev = pw->pw_histail;
  599.     plNew->pchLine = pchData;
  600.     if (pw->pw_histail)
  601.         pw->pw_histail->plNext = plNew;
  602.     else
  603.         pw->pw_hishead = plNew;
  604.     pw->pw_histail = plNew;
  605.     if (pw->nHistory >= pw->nHistMax)
  606.     {
  607.         plTemp = pw->pw_hishead;
  608.         pw->pw_hishead = plTemp->plNext;
  609.         pw->pw_hishead->plPrev = 0;
  610.         if (plTemp->pchLine)
  611.             free(plTemp->pchLine);
  612.         free(plTemp);
  613.     }
  614.     else
  615.     {
  616.         pw->nHistory++;
  617.     }
  618.     SetWindowText(pw->hEdit, "");
  619.     tkern_wakeup_call();
  620. }
  621.  
  622. static    BOOL
  623. CopyText(    HWND hWnd,
  624.         struct    per_window *pw)
  625. {
  626.     POINT    ptStart;
  627.     POINT    ptEnd;
  628.     int    i;
  629.     int    j;
  630.     int    nBytes;
  631.     struct    line *pl, *plSaved;
  632.     HGLOBAL    hmem;
  633.     char    *pchData;
  634.  
  635.     if (!pw->bMarkValid)
  636.     {
  637.         MessageBeep(MB_ICONSTOP);
  638.         return FALSE;
  639.     }
  640.     if (!OpenClipboard(hWnd))
  641.     {
  642.         MessageBeep(MB_ICONEXCLAMATION);
  643.         return FALSE;
  644.     }
  645.     EmptyClipboard();
  646.  
  647.     /* The clipboard wants CRLF separated lines. Figure out
  648.      * how many characters it will be.
  649.      */
  650.  
  651.     get_mark_coordinates(pw, &ptStart, &ptEnd);
  652.  
  653.     for (pl = pw->pw_tail, i = 0; pl && i < ptStart.y; pl = pl->plPrev, i++);
  654.     plSaved = pl;
  655.  
  656.     nBytes = 1; /* For the terminating NUL (not NULL) byte */
  657.  
  658.     while (i >= ptEnd.y)
  659.     {
  660.         nBytes += (pl->pchLine ? strlen(pl->pchLine) : 0);
  661.         if (ptEnd.y == i)
  662.             nBytes -= (pl->pchLine ? (strlen(pl->pchLine) - ptEnd.x) : 0);
  663.         else
  664.             nBytes += 2;
  665.         if (ptStart.y == i)
  666.             nBytes -= ptStart.x;
  667.  
  668.         i--;
  669.         pl = pl->plNext;
  670.     }
  671.  
  672.     hmem = GlobalAlloc(GMEM_MOVEABLE, nBytes);
  673.     pchData = GlobalLock(hmem);
  674.  
  675.     i = ptStart.y;
  676.     pl = plSaved;
  677.  
  678.     while (i >= ptEnd.y)
  679.     {
  680.         if (i == ptStart.y)
  681.             j = ptStart.x;
  682.         else
  683.             j = 0;
  684.  
  685.         if (i == ptEnd.y)
  686.         {
  687.             if (pl->pchLine)
  688.             {
  689.                 strncpy(pchData, pl->pchLine + j, ptEnd.x - j);
  690.                 pchData += ptEnd.x - j;
  691.             }
  692.         }
  693.         else
  694.         {
  695.             if (pl->pchLine)
  696.             {
  697.                 strcpy(pchData, pl->pchLine + j);
  698.                 pchData += strlen(pchData);
  699.             }
  700.             *pchData++ = '\r';
  701.             *pchData++ = '\n';
  702.         }
  703.         i--;
  704.         pl = pl->plNext;
  705.     }
  706.     *pchData = '\0';
  707.  
  708.     GlobalUnlock(hmem);
  709.     SetClipboardData(CF_TEXT, hmem);
  710.     CloseClipboard();
  711.     return TRUE;
  712. }
  713.  
  714. static    void
  715. PasteText(    HWND hWnd,
  716.         struct    per_window *pw)
  717. {
  718.     HGLOBAL    hmem;
  719.     char    *pchData;
  720.     char    *pchEOL;
  721.     char    *pchRemainder = 0;
  722.     char    *pchNow;
  723.     char    *pchTemp;
  724.     int    nTemp;
  725.     int    iRemainder;
  726.     DWORD    dwSelection;
  727.  
  728.     if (!OpenClipboard(hWnd))
  729.     {
  730.         MessageBeep(MB_ICONEXCLAMATION);
  731.         return;
  732.     }
  733.  
  734.     hmem = GetClipboardData(CF_TEXT);
  735.     if (!hmem)
  736.     {
  737.         MessageBeep(MB_ICONSTOP);
  738.         return;
  739.     }
  740.  
  741.     pchData = GlobalLock(hmem);
  742.  
  743.     while ((pchEOL = strchr(pchData, '\r')) != 0)
  744.     {
  745.         pchNow = malloc(pchEOL - pchData + 1);
  746.         strncpy(pchNow, pchData, pchEOL - pchData);
  747.         pchNow[pchEOL - pchData] = 0;
  748.         SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchNow);
  749.         free(pchNow);
  750.  
  751.         /* Remove the tail end of the line. This will get stuck
  752.          * back in once we get to the end of all this.
  753.          *
  754.          * Note that if we have done this once already, we know
  755.          * the selection is theoretically at the end of the window.
  756.          */
  757.  
  758.         if (!pchRemainder)
  759.         {
  760.             dwSelection = SendMessage(pw->hEdit, EM_GETSEL, 0, 0);
  761.             iRemainder = HIWORD(dwSelection);
  762.             nTemp = GetWindowTextLength(pw->hEdit);
  763.             pchTemp = malloc(nTemp + 1);
  764.             GetWindowText(pw->hEdit, pchTemp, nTemp + 1);
  765.             pchRemainder = malloc(nTemp - iRemainder + 1);
  766.             strcpy(pchRemainder, pchTemp + iRemainder);
  767.             pchTemp[iRemainder] = 0;
  768.             SetWindowText(pw->hEdit, pchTemp);
  769.             free(pchTemp);
  770.         }
  771.  
  772.         GotLine(pw);
  773.         pchData = pchEOL + 1;
  774.         if (*pchData == '\n')
  775.             pchData++;
  776.     }
  777.  
  778.     SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchData);
  779.     if (pchRemainder)
  780.     {
  781.         iRemainder = GetWindowTextLength(pw->hEdit);
  782.         SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchRemainder);
  783.         SendMessage(pw->hEdit, EM_SETSEL, TRUE, MAKELPARAM(iRemainder, iRemainder));
  784.         free(pchRemainder);
  785.     }
  786. }
  787.  
  788. static    void
  789. Scroll(    HWND    hWnd,
  790.     struct    per_window *pw,
  791.     WPARAM    wParam,
  792.     int    nPos)
  793. {
  794.     int    nNewPos;
  795.     RECT    rcScroll;
  796.     int    nRows;
  797.  
  798.     nNewPos = pw->nScrollPos;
  799.     GetClientRect(hWnd, &rcScroll);
  800.     rcScroll.bottom -= pw->cyChar + pw->cyChar / 5;
  801.     nRows = rcScroll.bottom / pw->cyChar - 1;
  802.  
  803.     switch(wParam)
  804.     {
  805.     case SB_BOTTOM:
  806.         nNewPos = 0;
  807.         break;
  808.  
  809.     case SB_LINEDOWN:
  810.         nNewPos--;
  811.         break;
  812.  
  813.     case SB_LINEUP:
  814.         nNewPos++;
  815.         break;
  816.  
  817.     case SB_PAGEUP:
  818.         nNewPos += nRows - 1;
  819.         break;
  820.  
  821.     case SB_PAGEDOWN:
  822.         nNewPos -= nRows - 1;
  823.         break;
  824.  
  825.     case SB_THUMBPOSITION:
  826.         nNewPos = nPos;
  827.         break;
  828.  
  829.     case SB_TOP:
  830.         nNewPos = pw->nLines;
  831.         break;
  832.     }
  833.     if (nNewPos > pw->nLines)
  834.         nNewPos = pw->nLines;
  835.     if (nNewPos < 0)
  836.         nNewPos = 0;
  837.  
  838.     SetScrollPos(hWnd, SB_VERT, pw->nLines - nNewPos, TRUE);
  839.     if (abs(pw->nScrollPos - nNewPos) >= nRows)
  840.         InvalidateRect(hWnd, &rcScroll, TRUE);
  841.     else
  842.         ScrollWindow(hWnd, 0,
  843.                  pw->cyChar * (nNewPos - pw->nScrollPos),
  844.                  &rcScroll, &rcScroll);
  845.     pw->nScrollPos = nNewPos;
  846.     if (nNewPos > 0)
  847.         pw->nUnscrolledLines = 0;
  848. }
  849.  
  850.  
  851. LRESULT    CALLBACK _export
  852. WindowProc(    HWND    hWnd,
  853.         UINT    wMsg,
  854.         WPARAM    wParam,
  855.         LPARAM    lParam)
  856. {
  857.     struct    per_window    *pw;
  858.     PAINTSTRUCT    ps;
  859.     TEXTMETRIC    tm;
  860.     HDC        hdc;
  861.  
  862.     pw = (struct per_window *) GetWindowLong(hWnd, 0);
  863.     switch(wMsg)
  864.     {
  865.     case WM_CREATE:
  866.         hdc = GetDC(hWnd);
  867.         GetTextMetrics(hdc, &tm);
  868.         ReleaseDC(hWnd, hdc);
  869.         pw = (struct per_window *) malloc(sizeof(struct per_window));
  870.         memset(pw, 0, sizeof(struct per_window));
  871.         pw->cxChar = tm.tmAveCharWidth;
  872.         pw->cyChar = tm.tmHeight + tm.tmExternalLeading;
  873.         pw->pw_head = (struct line *) malloc(sizeof(struct line));
  874.         pw->pw_tail = pw->pw_head;
  875.         pw->pw_head->plNext = pw->pw_head->plPrev = 0;
  876.         pw->pw_head->pchLine = 0;
  877.         pw->nHistMax = 20;
  878.         pw->nScrollLines = DEF_SCROLLLINES;
  879.         pw->nLinesMax = DEF_MAXLINES;
  880.         pw->nLines = 1;
  881.         pw->nUnscrolledLines = 0;
  882.         SetWindowLong(hWnd, 0, (long) pw);
  883.         PlaceEdit(hWnd, pw);
  884.         break;
  885.  
  886.     case WM_CLOSE:
  887.         if (!pw->bProgramClosed)
  888.         {
  889.             MessageBeep(MB_ICONSTOP);
  890.         }
  891.         else
  892.         {
  893.             window_destroy(hWnd);
  894.         }
  895.         return 0;
  896.  
  897.     case WM_PAINT:
  898.         PaintWindow(hWnd, pw);
  899.         return 0;
  900.  
  901.     case WM_SETFOCUS:
  902.         SetFocus(pw->hEdit);
  903.         return 0;
  904.  
  905.     case WM_LBUTTONDOWN:
  906.         MouseDown(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
  907.         break;
  908.  
  909.     case WM_MOUSEMOVE:
  910.         if (pw->bHaveMouse)
  911.             MouseMove(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
  912.         break;
  913.  
  914.     case WM_LBUTTONUP:
  915.         if (pw->bHaveMouse)
  916.             MouseUp(pw);
  917.         break;
  918.  
  919.     case WM_VSCROLL:
  920.         Scroll(hWnd, pw, wParam, LOWORD(lParam));
  921.         break;
  922.  
  923.     case WM_SYSCOMMAND:
  924.         switch(wParam)
  925.         {
  926.         case SC_COPY:
  927.             CopyText(hWnd, pw);
  928.             break;
  929.  
  930.         case SC_PASTE:
  931.             PasteText(hWnd, pw);
  932.             break;
  933.  
  934.         case SC_COPYPASTE:
  935.             if (CopyText(hWnd, pw))
  936.                 PasteText(hWnd, pw);
  937.             break;
  938.         }
  939.         break;
  940.  
  941.     case ENTER_HIT:
  942.         GotLine(pw);
  943.         break;
  944.  
  945.     case UP_HIT:
  946.         if (pw->pw_history)
  947.         {
  948.             if (pw->pw_history->plPrev)
  949.             {
  950.                 pw->pw_history = pw->pw_history->plPrev;
  951.             }
  952.             else
  953.             {
  954.                 MessageBeep(MB_ICONEXCLAMATION);
  955.                 break;
  956.             }
  957.         }
  958.         else if (pw->pw_histail)
  959.         {
  960.             pw->pw_history = pw->pw_histail;
  961.         }
  962.         else
  963.         {
  964.             MessageBeep(MB_ICONEXCLAMATION);
  965.             break;
  966.         }
  967.         SetWindowText(pw->hEdit, pw->pw_history->pchLine);
  968.         break;
  969.  
  970.     case DOWN_HIT:
  971.         if (pw->pw_history)
  972.         {
  973.             if (pw->pw_history->plNext)
  974.             {
  975.                 pw->pw_history = pw->pw_history->plNext;
  976.             }
  977.             else
  978.             {
  979.                 MessageBeep(MB_ICONEXCLAMATION);
  980.                 break;
  981.             }
  982.         }
  983.         else if (pw->pw_hishead)
  984.         {
  985.             pw->pw_history = pw->pw_hishead;
  986.         }
  987.         else
  988.         {
  989.             MessageBeep(MB_ICONEXCLAMATION);
  990.             break;
  991.         }
  992.         SetWindowText(pw->hEdit, pw->pw_history->pchLine);
  993.         break;
  994.     }
  995.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  996. }
  997.  
  998.  
  999.  
  1000. #pragma argsused
  1001. int
  1002. window_open(    char    const *pchPath,
  1003.         int    iMode,
  1004.         int    iAccess)
  1005. {
  1006.     HWND    hWnd;
  1007.     HMENU    hmenuSys;
  1008.  
  1009.     if (!bRegistered)
  1010.     {
  1011.         WNDCLASS wc;
  1012.  
  1013.         wc.style = CS_GLOBALCLASS |
  1014.                CS_HREDRAW |
  1015.                CS_VREDRAW;
  1016.         wc.lpfnWndProc = WindowProc;
  1017.         wc.cbClsExtra = 0;
  1018.         wc.cbWndExtra = sizeof(struct per_window *);
  1019.         wc.hInstance = hInstance;
  1020.         wc.hIcon = LoadIcon(hInstance, "TKERN_ICO");
  1021.         wc.hCursor = (HCURSOR) IDC_IBEAM;
  1022.         wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  1023.         wc.lpszMenuName = 0;
  1024.         wc.lpszClassName = "Troy's Kernel Window";
  1025.         RegisterClass(&wc);
  1026.     }
  1027.  
  1028.     hWnd = CreateWindow(    "Troy's Kernel Window",
  1029.                 pchPath,
  1030.                 WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  1031.                 CW_USEDEFAULT,
  1032.                 0,
  1033.                 CW_USEDEFAULT,
  1034.                 0,
  1035.                 0,
  1036.                 0,
  1037.                 hInstance,
  1038.                 0
  1039.             );
  1040.     if (!hWnd)
  1041.     {
  1042.         nError = ENOMEM;
  1043.         return -1;
  1044.     }
  1045.     else
  1046.     {
  1047.         LockManager();
  1048.         hmenuSys = GetSystemMenu(hWnd, FALSE);
  1049.         AppendMenu(hmenuSys, MF_SEPARATOR, 0, 0);
  1050.         AppendMenu(hmenuSys, MF_STRING, SC_COPY, "C&opy");
  1051.         AppendMenu(hmenuSys, MF_STRING, SC_PASTE, "&Paste");
  1052.         AppendMenu(hmenuSys, MF_STRING, SC_COPYPASTE, "Cop&y and Paste");
  1053.         EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
  1054.         ShowWindow(hWnd, SW_SHOW);
  1055.         return (int) hWnd;
  1056.     }
  1057. }
  1058.  
  1059. static    void
  1060. add_to_line(    struct    line    *pl,
  1061.         char    const    *pchBuffer,
  1062.         int    nBytes)
  1063. {
  1064.     char    *pchString;
  1065.  
  1066.     if (!nBytes)
  1067.         return;
  1068.     pchString = (char *) malloc(nBytes +
  1069.             (pl->pchLine ? strlen(pl->pchLine) : 0) + 1);
  1070.     if (pl->pchLine)
  1071.         strcpy(pchString, pl->pchLine);
  1072.     else
  1073.         *pchString = 0;
  1074.     pchString[strlen(pchString) + nBytes] = 0;
  1075.     memcpy(pchString + strlen(pchString), pchBuffer, nBytes);
  1076.     if (pl->pchLine)
  1077.         free(pl->pchLine);
  1078.     pl->pchLine = pchString;
  1079. }
  1080.         
  1081.  
  1082. int
  1083. window_write(    int    id,
  1084.         char    const *pchBuffer,
  1085.         int    nBytes)
  1086. {
  1087.     HWND    hWnd = (HWND) id;
  1088.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1089.     int    nLines = 0;
  1090.     char    *pchNewLine;
  1091.     char    const *c = pchBuffer;
  1092.     struct    line *plTemp;
  1093.     int    nLeft = nBytes;
  1094.     RECT    rcRedraw;
  1095.  
  1096.     if (!nBytes)
  1097.         return 0;
  1098.  
  1099.     while (nLeft--)
  1100.     {
  1101.         if (*c++ == '\n')
  1102.         {
  1103.             add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer - 1);
  1104.             plTemp = (struct line *) malloc(sizeof(struct line));
  1105.             plTemp->pchLine = 0;
  1106.             plTemp->plNext = 0;
  1107.             plTemp->plPrev = pw->pw_tail;
  1108.             pw->pw_tail->plNext = plTemp;
  1109.             pw->pw_tail = plTemp;
  1110.             pchBuffer = c;
  1111.             nLines++;
  1112.         }
  1113.     }
  1114.     if (c != pchBuffer)
  1115.         add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer);
  1116.     GetClientRect(hWnd, &rcRedraw);
  1117.     rcRedraw.top = rcRedraw.bottom - pw->cyChar - pw->cyChar / 5 * 2;
  1118.     InvalidateRect(hWnd, &rcRedraw, TRUE);
  1119.     if (nLines)
  1120.     {
  1121.         /* Rather than scrolling every line, which
  1122.          * is somewhat slow, scroll after some
  1123.          * number of lines as set by the user.
  1124.          * This is processed via a posted message,
  1125.          * so once an app starts flushing messages,
  1126.          * any outstanding scrolling should be
  1127.          * processed.
  1128.          */
  1129.         if (!pw->nScrollPos)
  1130.         {
  1131.             pw->nUnscrolledLines += nLines;
  1132.             if (pw->nUnscrolledLines >= pw->nScrollLines)
  1133.                 FlushMessages();
  1134.         }
  1135.         MoveMark(pw, nLines);
  1136.         pw->nLines += nLines;
  1137.         while (pw->nLines > pw->nLinesMax)
  1138.         {
  1139.             plTemp = pw->pw_head;
  1140.             pw->pw_head = plTemp->plNext;
  1141.             if (plTemp->pchLine)
  1142.                 free(plTemp->pchLine);
  1143.             free(plTemp);
  1144.             pw->pw_head->plPrev = 0;
  1145.             pw->nLines--;
  1146.         }
  1147.         if (pw->nScrollPos)
  1148.             pw->nScrollPos += nLines;
  1149.         SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
  1150.         SetScrollPos(hWnd, SB_VERT, pw->nLines - pw->nScrollPos, TRUE);
  1151.     }
  1152.     return    nBytes;
  1153. }
  1154.  
  1155. int
  1156. window_read(    int    id,
  1157.         char    *pchBuffer,
  1158.         int    nBytes)
  1159. {
  1160.     HWND    hWnd = (HWND) id;
  1161.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1162.     struct    line    *pl;
  1163.     char    *pchNewLine;
  1164.     int    iLen;
  1165.  
  1166.     if (!pw->pw_inhead)
  1167.         return FR_NOTREADY;
  1168.  
  1169.     pl = pw->pw_inhead;
  1170.  
  1171.     iLen = strlen(pl->pchLine);
  1172.     if (iLen >= nBytes)
  1173.     {
  1174.         memcpy(pchBuffer, pl->pchLine, nBytes);
  1175.         pchNewLine = (char *) malloc(iLen + 1 - nBytes);
  1176.         memcpy(pchNewLine, pl->pchLine + nBytes, iLen + 1 - nBytes);
  1177.         free(pl->pchLine);
  1178.         pl->pchLine = pchNewLine;
  1179.     }
  1180.     else
  1181.     {
  1182.         memcpy(pchBuffer, pl->pchLine, iLen);
  1183.         pchBuffer[iLen] = '\n';
  1184.         pw->pw_inhead = pl->plNext;
  1185.         if (!pl->plNext)
  1186.             pw->pw_intail = 0;
  1187.         free(pl->pchLine);
  1188.         free(pl);
  1189.         nBytes = iLen + 1;
  1190.     }
  1191.     window_write(id, pchBuffer, nBytes);
  1192.     return nBytes;
  1193. }
  1194.  
  1195. int
  1196. window_close(    int    id)
  1197. {
  1198.     HWND    hWnd = (HWND) id;
  1199.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1200.     HMENU    hmenuSys = GetSystemMenu(hWnd, TRUE);
  1201.     char    *pchOldText;
  1202.     char    *pchNewText;
  1203.     int    nTextLen;
  1204.  
  1205.     EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
  1206.     pw->bProgramClosed = TRUE;
  1207.     nTextLen = GetWindowTextLength(hWnd);
  1208.     pchOldText = (char *) malloc(nTextLen + 1);
  1209.     GetWindowText(hWnd, pchOldText, nTextLen + 1);
  1210.     pchOldText[nTextLen] = 0;
  1211.     pchNewText = malloc(nTextLen + 12);
  1212.     strcpy(pchNewText, "(Inactive ");
  1213.     strcat(pchNewText, pchOldText);
  1214.     strcat(pchNewText, ")");
  1215.     free(pchOldText);
  1216.     SetWindowText(hWnd, pchNewText);
  1217.     free(pchNewText);
  1218.     return 0;
  1219. }
  1220.  
  1221. static int
  1222. window_destroy(HWND hWnd)
  1223. {
  1224.     struct    line    *pl, *plNext;
  1225.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1226.  
  1227.     DestroyWindow(hWnd);
  1228.     for (pl = pw->pw_head; pl; pl = plNext)
  1229.     {
  1230.         plNext = pl->plNext;
  1231.         if (pl->pchLine)
  1232.             free(pl->pchLine);
  1233.         free(pl);
  1234.     }
  1235.     for (pl = pw->pw_hishead; pl; pl = plNext)
  1236.     {
  1237.         plNext = pl->plNext;
  1238.         if (pl->pchLine)
  1239.             free(pl->pchLine);
  1240.         free(pl);
  1241.     }
  1242.     for (pl = pw->pw_inhead; pl; pl = plNext)
  1243.     {
  1244.         plNext = pl->plNext;
  1245.         if (pl->pchLine)
  1246.             free(pl->pchLine);
  1247.         free(pl);
  1248.     }
  1249.     free(pw);
  1250.     UnlockManager();
  1251.     return 0;
  1252. }
  1253.  
  1254. void
  1255. CheckLimits(    HWND    hWnd,
  1256.         struct per_window *pw)
  1257. {
  1258.     struct    line    *plTemp;
  1259.  
  1260.     while (pw->nLines > pw->nLinesMax)
  1261.     {
  1262.         plTemp = pw->pw_head;
  1263.         pw->pw_head = plTemp->plNext;
  1264.         if (plTemp->pchLine)
  1265.             free(plTemp->pchLine);
  1266.         free(plTemp);
  1267.         pw->pw_head->plPrev = 0;
  1268.         pw->nLines--;
  1269.     }
  1270.  
  1271.     while (pw->nHistory > pw->nHistMax)
  1272.     {
  1273.         plTemp = pw->pw_hishead;
  1274.         pw->pw_hishead = plTemp->plNext;
  1275.         pw->pw_hishead->plPrev = 0;
  1276.         if (plTemp->pchLine)
  1277.             free(plTemp->pchLine);
  1278.         free(plTemp);
  1279.         pw->nHistory--;
  1280.     }
  1281.     pw->pw_history = 0;
  1282.     SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
  1283. }
  1284.  
  1285. void
  1286. GetWindowSize(    HWND    hWnd,
  1287.         struct per_window *pw,
  1288.         struct winsize *wsize)
  1289. {
  1290.     RECT    rcWindow;
  1291.  
  1292.     GetClientRect(hWnd, &rcWindow);
  1293.     wsize->ws_xpixel = rcWindow.right;
  1294.     wsize->ws_ypixel = rcWindow.bottom;
  1295.     wsize->ws_col = rcWindow.right / pw->cxChar;
  1296.     wsize->ws_row = (rcWindow.bottom - pw->cyChar / 5 * 2) / pw->cyChar;
  1297. }
  1298.  
  1299. void
  1300. SetWindowSize(    HWND    hWnd,
  1301.         struct per_window *pw,
  1302.         struct winsize *wsize)
  1303. {
  1304.     RECT    rcClient;
  1305.     RECT    rcWindow;
  1306.     int    xExtra;
  1307.     int    yExtra;
  1308.     int    xSize;
  1309.     int    ySize;
  1310.  
  1311.     GetClientRect(hWnd, &rcClient);
  1312.     GetWindowRect(hWnd, &rcWindow);
  1313.     xExtra = (rcWindow.right - rcWindow.left) - rcClient.right;
  1314.     yExtra = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
  1315.  
  1316.     if (wsize->ws_col)
  1317.         xSize = wsize->ws_col * pw->cxChar;
  1318.     else if (wsize->ws_xpixel)
  1319.         xSize = wsize->ws_xpixel;
  1320.     else
  1321.         xSize = rcClient.right;
  1322.  
  1323.     if (wsize->ws_row)
  1324.         ySize = wsize->ws_row * pw->cyChar + pw->cyChar / 5 * 2;
  1325.     else if (wsize->ws_ypixel)
  1326.         ySize = wsize->ws_ypixel;
  1327.     else
  1328.         ySize = rcClient.bottom;
  1329.  
  1330.     MoveWindow(hWnd,
  1331.             rcWindow.left,
  1332.             rcWindow.top,
  1333.             xSize + xExtra,
  1334.             ySize + yExtra,
  1335.             TRUE);
  1336. }
  1337.  
  1338. int
  1339. window_ioctl(    int    fd,
  1340.         struct tk_ioctl *tki)
  1341. {
  1342.     HWND    hWnd = (HWND) fd;
  1343.     struct    wio_parms * const wiop = (struct wio_parms *) tki->achBuffer;
  1344.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1345.  
  1346.     switch(tki->nIOCtl)
  1347.     {
  1348.     case WIOCGETHANDLE:
  1349.         return fd;
  1350.  
  1351.     case WIOCGETNAME:
  1352.         return GetWindowText(hWnd, tki->achBuffer, tki->nSize);
  1353.  
  1354.     case WIOCSETNAME:
  1355.         SetWindowText(hWnd, tki->achBuffer);
  1356.         return 0;
  1357.  
  1358.     case WIOCGETPARMS:
  1359.         wiop->wiop_display_lines = pw->nLinesMax;
  1360.         wiop->wiop_history_lines = pw->nHistMax;
  1361.         wiop->wiop_scroll_lines = pw->nScrollLines;
  1362.         return 0;
  1363.  
  1364.     case WIOCSETPARMS:
  1365.         pw->nLinesMax = wiop->wiop_display_lines;
  1366.         pw->nHistMax = wiop->wiop_history_lines;
  1367.         pw->nScrollLines = wiop->wiop_scroll_lines;
  1368.         CheckLimits(hWnd, pw);
  1369.         return 0;
  1370.  
  1371.     case TIOCGWINSZ:
  1372.         GetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
  1373.         return 0;
  1374.  
  1375.     case TIOCSWINSZ:
  1376.         SetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
  1377.         return 0;
  1378.  
  1379.     default:
  1380.         nError = EINVAL;
  1381.         return -1;
  1382.     }
  1383. }
  1384.